package com.lb.ai.common.generator;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
 * MyBatis-Plus代码生成器
 * 支持MySQL和PostgreSQL数据库
 * 可以生成Entity、Mapper、Service、Controller等各层代码
 * 支持Java8日期时间类型和传统Date类型的选择
 * 支持Swagger注解的开启与关闭
 * 支持表前缀的处理
 *
 * @author Your Name
 * @since 2024-01-01
 */
@Data
@Accessors(chain = true)
public class CodeGenerator {
    /** 项目根路径 */
    private static final String PROJECT_PATH = System.getProperty("user.dir");
    /** Java源码路径 */
    private static final String JAVA_PATH = "/src/main/java";
    /** 资源文件路径 */
    private static final String RESOURCES_PATH = "/src/main/resources";
    /** Mapper XML文件路径 */
    private static final String MAPPER_XML_PATH = RESOURCES_PATH + "/mapper/";

    /**
     * 数据库类型
     * 支持MySQL和PostgreSQL
     */
    private DbType dbType;

    /**
     * 数据库连接URL
     * MySQL示例: jdbc:mysql://localhost:3306/database
     * PostgreSQL示例: jdbc:postgresql://localhost:5432/database
     */
    private String url;

    /**
     * 数据库用户名
     */
    private String username;

    /**
     * 数据库密码
     */
    private String password;

    /**
     * 代码生成的目标包名
     * 例如: com.company.project
     */
    private String packageName;

    /**
     * 代码生成的目标模块名
     * 会作为包名的一部分，例如: user, order等
     */
    private String moduleName;

    /**
     * 代码作者
     * 会在生成的代码注释中标注
     */
    private String author;

    /**
     * 要生成代码的表名数组
     * 例如: ["user", "role", "permission"]
     */
    private String[] tables;

    /**
     * 表前缀数组
     * 例如: ["t_", "sys_"]
     * 生成代码时会自动去除这些前缀
     */
    private String[] tablePrefix;

    /**
     * 是否忽略表前缀
     * true: 保留表前缀
     * false: 移除表前缀（默认）
     */
    private boolean ignoreTablePrefix = false;

    /**
     * 代码输出目录
     * 默认为项目的src/main/java目录
     */
    private String outputDir;

    /**
     * 是否启用Swagger注解
     * true: 生成Swagger注解
     * false: 不生成Swagger注解（默认）
     */
    private boolean enableSwagger = false;

    /**
     * 是否启用SpringDoc注解
     * true: 生成SpringDoc注解
     * false: 不生成SpringDoc注解（默认）
     */
    private boolean enableSpringDoc = false;

    /**
     * 是否生成Controller层代码
     * 默认为true
     */
    private boolean generateController = true;

    /**
     * 是否生成Service层代码
     * 默认为true
     */
    private boolean generateService = true;

    /**
     * 是否生成Mapper层代码
     * 默认为true
     */
    private boolean generateMapper = true;

    /**
     * 是否生成Entity实体类
     * 默认为true
     */
    private boolean generateEntity = true;

    /**
     * 是否使用Java8新的日期时间类型
     * true: 使用LocalDateTime等（默认）
     * false: 使用java.util.Date
     */
    private boolean useJava8DateType = true;

    /**
     * 数据库类型枚举
     */
    public enum DbType {
        /** MySQL数据库 */
        MYSQL,
        /** PostgreSQL数据库 */
        POSTGRESQL
    }

    /**
     * 执行代码生成
     * 根据配置生成相应的代码文件
     */
    public void generate() {
        // 如果没有设置输出目录，使用默认的项目路径
        if (outputDir == null || outputDir.isEmpty()) {
            outputDir = PROJECT_PATH + "/" + moduleName + JAVA_PATH;
        }

        // 确保输出目录存在
        File dir = new File(outputDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // XML文件输出路径
        String mapperXmlPath = PROJECT_PATH + "/" + moduleName + MAPPER_XML_PATH;
        File mapperXmlDir = new File(mapperXmlPath);
        if (!mapperXmlDir.exists()) {
            mapperXmlDir.mkdirs();
        }

        // 配置输出路径Map
        Map<OutputFile, String> pathInfo = new HashMap<>();
        if (generateMapper) {
            pathInfo.put(OutputFile.xml, mapperXmlPath);
        }

        // 数据源配置
        DataSourceConfig.Builder dataSourceConfig = new DataSourceConfig
                .Builder(url, username, password);

        FastAutoGenerator.create(dataSourceConfig)
                // 全局配置
                .globalConfig(builder -> {
                    builder.author(author)
                            .dateType(useJava8DateType ? DateType.TIME_PACK : DateType.ONLY_DATE)
                            .commentDate("yyyy-MM-dd")
                            .outputDir(outputDir)
                            .disableOpenDir();

                    // 根据配置决定是否启用Swagger注解
                    if (enableSwagger) {
                        builder.enableSwagger();
                    }

                    // 根据配置决定是否启用Swagger注解
                    if (enableSpringDoc) {
                        builder.enableSpringdoc();
                    }
                })
                // 包配置
                .packageConfig(builder -> {
                    builder.parent(packageName)
                            .entity("model")
                            .service("service")
                            .serviceImpl("service.impl")
                            .mapper("mapper")
                            .xml("mapper.xml")
                            .controller("controller")
                            .pathInfo(pathInfo);
                })
                // 策略配置
                .strategyConfig(builder -> {
                    builder.addInclude(tables);

                    // 只有在不忽略表前缀且有表前缀配置的情况下才添加表前缀
                    if (!ignoreTablePrefix && tablePrefix != null && tablePrefix.length > 0) {
                        builder.addTablePrefix(tablePrefix);
                    }

                    // Entity策略配置
                    if (generateEntity) {
                        builder.entityBuilder()
                                .enableLombok()
                                .enableChainModel()
                                .naming(NamingStrategy.underline_to_camel)
                                .columnNaming(NamingStrategy.underline_to_camel)
                                .idType(IdType.AUTO)
                                .formatFileName("%s")
                                .enableTableFieldAnnotation();
                    }

                    // Controller策略配置
                    if (generateController) {
                        builder.controllerBuilder()
                                .enableRestStyle()
                                .formatFileName("%sController");
                    }

                    // Service策略配置
                    if (generateService) {
                        builder.serviceBuilder()
                                .formatServiceFileName("I%sService")
                                .formatServiceImplFileName("%sServiceImpl");
                    }

                    // Mapper策略配置
                    if (generateMapper) {
                        builder.mapperBuilder()
                                .enableMapperAnnotation()
                                .enableBaseResultMap()  // 启用BaseResultMap
                                .enableBaseColumnList() // 启用BaseColumnList
                                .formatMapperFileName("%sMapper")
                                .formatXmlFileName("%sMapper");
                    }
                })
                // 模板引擎配置
                .templateEngine(new VelocityTemplateEngine())
                .execute();
    }

    /**
     * 创建代码生成器构建器
     * @return 代码生成器构建器实例
     */
    public static CodeGeneratorBuilder builder() {
        return new CodeGeneratorBuilder();
    }

    /**
     * 代码生成器构建器
     * 使用建造者模式，方便链式调用配置
     */
    public static class CodeGeneratorBuilder {
        /** 代码生成器实例 */
        private final CodeGenerator instance = new CodeGenerator();

        /**
         * 配置MySQL数据库
         * @return 构建器实例
         */
        public CodeGeneratorBuilder mysql() {
            instance.setDbType(DbType.MYSQL);
            return this;
        }

        /**
         * 配置PostgreSQL数据库
         * @return 构建器实例
         */
        public CodeGeneratorBuilder postgresql() {
            instance.setDbType(DbType.POSTGRESQL);
            return this;
        }

        /**
         * 配置数据库连接URL
         * @param url 数据库连接URL
         * @return 构建器实例
         */
        public CodeGeneratorBuilder url(String url) {
            instance.setUrl(url);
            return this;
        }

        /**
         * 配置数据库用户名
         * @param username 数据库用户名
         * @return 构建器实例
         */
        public CodeGeneratorBuilder username(String username) {
            instance.setUsername(username);
            return this;
        }

        /**
         * 配置数据库密码
         * @param password 数据库密码
         * @return 构建器实例
         */
        public CodeGeneratorBuilder password(String password) {
            instance.setPassword(password);
            return this;
        }

        /**
         * 配置包名
         * @param packageName 包名
         * @return 构建器实例
         */
        public CodeGeneratorBuilder packageName(String packageName) {
            instance.setPackageName(packageName);
            return this;
        }

        /**
         * 配置模块名
         * @param moduleName 模块名
         * @return 构建器实例
         */
        public CodeGeneratorBuilder moduleName(String moduleName) {
            instance.setModuleName(moduleName);
            return this;
        }

        /**
         * 配置作者
         * @param author 作者名
         * @return 构建器实例
         */
        public CodeGeneratorBuilder author(String author) {
            instance.setAuthor(author);
            return this;
        }

        /**
         * 配置要生成代码的表名
         * @param tables 表名数组
         * @return 构建器实例
         */
        public CodeGeneratorBuilder tables(String... tables) {
            instance.setTables(tables);
            return this;
        }

        /**
         * 配置表前缀
         * @param tablePrefix 表前缀数组
         * @return 构建器实例
         */
        public CodeGeneratorBuilder tablePrefix(String... tablePrefix) {
            instance.setTablePrefix(tablePrefix);
            return this;
        }

        /**
         * 配置是否忽略表前缀
         * @param ignore true:保留表前缀 false:移除表前缀
         * @return 构建器实例
         */
        public CodeGeneratorBuilder ignoreTablePrefix(boolean ignore) {
            instance.setIgnoreTablePrefix(ignore);
            return this;
        }

        /**
         * 配置输出目录
         * @param outputDir 代码输出目录
         * @return 构建器实例
         */
        public CodeGeneratorBuilder outputDir(String outputDir) {
            instance.setOutputDir(outputDir);
            return this;
        }

        /**
         * 配置是否启用Swagger注解
         * @param enable true:启用 false:禁用
         * @return 构建器实例
         */
        public CodeGeneratorBuilder enableSwagger(boolean enable) {
            instance.setEnableSwagger(enable);
            return this;
        }

        /**
         * 配置是否启用SpringDoc注解
         * @param enable true:启用 false:禁用
         * @return 构建器实例
         */
        public CodeGeneratorBuilder enableSpringDoc(boolean enable) {
            instance.setEnableSpringDoc(enable);
            return this;
        }

        /**
         * 配置是否生成Controller层代码
         * @param generate true:生成 false:不生成
         * @return 构建器实例
         */
        public CodeGeneratorBuilder generateController(boolean generate) {
            instance.setGenerateController(generate);
            return this;
        }

        /**
         * 配置是否生成Service层代码
         * @param generate true:生成 false:不生成
         * @return 构建器实例
         */
        public CodeGeneratorBuilder generateService(boolean generate) {
            instance.setGenerateService(generate);
            return this;
        }

        /**
         * 配置是否生成Mapper层代码
         * @param generate true:生成 false:不生成
         * @return 构建器实例
         */
        public CodeGeneratorBuilder generateMapper(boolean generate) {
            instance.setGenerateMapper(generate);
            return this;
        }

        /**
         * 配置是否生成Entity实体类
         * @param generate true:生成 false:不生成
         * @return 构建器实例
         */
        public CodeGeneratorBuilder generateEntity(boolean generate) {
            instance.setGenerateEntity(generate);
            return this;
        }

        /**
         * 配置是否使用Java8日期时间类型
         * @param useJava8 true:使用LocalDateTime等 false:使用Date
         * @return 构建器实例
         */
        public CodeGeneratorBuilder useJava8DateType(boolean useJava8) {
            instance.setUseJava8DateType(useJava8);
            return this;
        }

        /**
         * 构建代码生成器实例
         * @return 配置完成的代码生成器实例
         */
        public CodeGenerator build() {
            return instance;
        }
    }
} 